package cn.wen.forum.service.impl;

import cn.wen.forum.common.enums.ResultCode;
import cn.wen.forum.common.exception.ServiceException;
import cn.wen.forum.common.result.JSONResult;
import cn.wen.forum.common.result.Result;
import cn.wen.forum.common.util.*;
import cn.wen.forum.config.InitSysParams;
import cn.wen.forum.config.JWTConfig;
import cn.wen.forum.constants.ForumConstant;
import cn.wen.forum.mapper.UserMapper;
import cn.wen.forum.pojo.entity.User;
import cn.wen.forum.service.IUserService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.UUID;

/**
 * @ClassName UserServiceIml
 * @Author By wen
 * @Description
 * @Date 2023/3/16 10:37
 * @Version 1.0
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {


    @Autowired
    public RedisUtils redisUtils;

    @Autowired
    private UserMapper userMapper;

    private final static Long EXPIRE_TIME = 24 * 60 * 60 * 1000L;

    private final static int EXPIRE_TIME_INT = 24 * 60 * 60;

    /**
     * 用户登录
     *
     * @param user
     * @return
     */
    @Override
    public JSONResult login(User user,HttpServletResponse response) throws Exception {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if(StringUtils.isBlank(user.getUserAccount())
                || StringUtils.isBlank(user.getPassword())
        ){
            throw new ServiceException(ResultCode.PARAM_IS_BLANK,"用户账号或者密码为空！");
        }
        wrapper.eq("user_account",user.getUserAccount());
        User userEntity = userMapper.selectOne(wrapper);
        if(userEntity == null){
            return Result.fail(ResultCode.USER_ACCOUNT_NOT_EXIST_OR_CREDENTIALS_ERROR);
        } else{
            String pw = RSAUtils.decrypt(userEntity.getPassword(),InitSysParams.getSysParamByID("PRI_KEY"));
            if(!StringUtils.equals(pw,user.getPassword())) {
                return Result.fail(ResultCode.USER_ACCOUNT_NOT_EXIST_OR_CREDENTIALS_ERROR);
            }
            // 判断是否今日第一次登录
            if (!DateUtils.isNowDay(userEntity.getLastLoginTime())) {
                // 每日第一次登录，更新经验值
                // 重置每天评论发布点赞信息
                // userInfo.setDayReviewNum(0);
                // userInfo.setDayPushPostNum(0);
                // userInfo.setDayApprovalNum(0);
                LevelUtils.updateEmpiricalValue(userEntity.getId(),ForumConstant.ADD_TYPE_LOGIN,true);
            }
            // 更新user最后一次登录时间
            userEntity.setLastLoginTime(new Date());
            userEntity.setLoginTimeStr(DateUtils.parseToDateStr(new Date()));
            userMapper.updateById(userEntity);
            // 设置过期时间
            userEntity.setExpireTime(System.currentTimeMillis() + EXPIRE_TIME);
            // 根据uuid来生成用户的key，用于从redis获取user信息
            String userKey = UUID.randomUUID().toString() + "_" + userEntity.getId();
            String jwtToken = JWTConfig.getJwtToken(userKey,userEntity);
            // 写入当前用户登录信息（仅用于登录验证操作）
            redisUtils.setCacheObject(userKey,userEntity);

            // 设置每日活跃用户缓存 
//            Set activeUserSet = redisUtils.getCacheSet(ForumConstant.USER_ACTIVE_INFO);
//            if(StringUtils.isNull(activeUserSet)) {
//                activeUserSet = new HashSet<String>();
//            }
//            activeUserSet.add(userEntity.getId()+"");
//            redisUtils.setCacheSet(ForumConstant.USER_ACTIVE_INFO,activeUserSet);

            userEntity.setJwt(jwtToken);
            return Result.success(userEntity);
        }
    }

    /**
     * 注册
     *
     * @param user
     * @return
     */
    @Override
    public JSONResult register(User user, HttpServletResponse response) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if(StringUtils.isBlank(user.getUserAccount())
                || StringUtils.isBlank(user.getUserName())
                || StringUtils.isBlank(user.getPassword())
        ){
            throw new ServiceException(ResultCode.PARAM_IS_BLANK);
        }
        wrapper.eq("user_account", user.getUserAccount());
        User userEntity = userMapper.selectOne(wrapper);
        if (userEntity == null) {
            // 加密
            try {
                user.setPassword(RSAUtils.encrypt(user.getPassword(),InitSysParams.getSysParamByID("PUB_KEY")));
            } catch (Exception e) {
                log.error("=====密码加密异常：",e);
            }
            user.setApprovalNum(0l);
            user.setPostNum(0l);
            user.setAttentionNum(0l);
            user.setCollectNum(0l);
            user.setReviewNum(0l);
            user.setCreateTime(new Date());
            user.setLevel(1);
            user.setEmpiricalValue(1);
            int i = userMapper.insert(user);
            if (i > 0) {
                /*// 再次查询成功插入的user数据
                user = userMapper.selectOne(wrapper);
                // 创建jwt对象并存入请求头
                String userKey = UUID.randomUUID().toString() + "_" + user.getId();
                String jwtToken = JWTConfig.getJwtToken(userKey,user);
                // 设置过期时间
                user.setExpireTime(System.currentTimeMillis() + EXPIRE_TIME);
                redisUtils.setCacheObject(userKey,user);*/
                return Result.success();
            }
            return Result.fail(ResultCode.DATA_WRITE_ERROR);
        } else {
            return Result.fail(ResultCode.USER_ACCOUNT_ALREADY_EXIST);
        }
    }

    /**
     * 从token中获取用户信息
     *
     * @param request
     * @return
     */
    @Override
    public JSONResult getUser(HttpServletRequest request) throws Exception{
        String token = request.getHeader("Authorization");
        if(StringUtils.isEmpty(token)){
            return Result.fail(ResultCode.USER_NOT_LOGIN);
        }
        if(!token.startsWith("Bearer:")){
            return Result.fail(ResultCode.USER_TOKEN_ILLEGAL);
        }
        String userKey = JWTConfig.parseJWT(request);
        if(userKey != null){
            Object cacheObject = redisUtils.getCacheObject(userKey);
            if(cacheObject == null){
                return Result.fail(ResultCode.USER_NOT_LOGIN);
            }
            User user = JSONObject.parseObject(cacheObject.toString(), User.class);
            if(user.getExpireTime() - System.currentTimeMillis() > 0){
                if(user.getExpireTime() - System.currentTimeMillis() < 20 * 60 * 1000L){
                    // 当过期时间不足20分钟时，刷新token，并刷新redis缓存
                    user.setExpireTime(System.currentTimeMillis() + EXPIRE_TIME);
                    String newUserKey = UUID.randomUUID().toString() + "_" + user.getId();
                    String newToken = JWTConfig.getJwtToken(userKey,user);
                    redisUtils.deleteObject(userKey);
                    redisUtils.setCacheObject(newUserKey,user);
                    user.setJwt(newToken);
                } else{
                    user.setJwt(token.substring(token.indexOf(":")+1));
                }
                // 判断是否今日第一次登录
                if (!DateUtils.isNowDay(DateUtils.parseToDate(user.getLoginTimeStr()))) {
                    // 每日第一次登录，更新经验值+
                    LevelUtils.updateEmpiricalValue(user.getId(),ForumConstant.ADD_TYPE_LOGIN,true);

                    user.setLoginTimeStr(DateUtils.parseToDateStr(new Date()));
                    redisUtils.setCacheObject(userKey,user);
                }
                user.setPassword("");
                return Result.success(user);
            } else {
                redisUtils.deleteObject(userKey);
                return Result.fail(ResultCode.USER_LOGIN_PAST_DUE);
            }
        } else {
            return Result.fail(ResultCode.USER_TOKEN_ILLEGAL);
        }

    }
    

    /**
     * 退出登录
     *
     * @param request
     * @return
     */
    @Override
    public JSONResult logout(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if(StringUtils.isEmpty(token)){
            return Result.fail(ResultCode.USER_NOT_LOGIN);
        }
        if(!token.startsWith("Bearer:")){
            return Result.fail(ResultCode.USER_TOKEN_ILLEGAL);
        }
        String userKey = JWTConfig.parseJWT(request);
        redisUtils.deleteObject(userKey);
        return Result.success();
    }
}